package com.huanglejing.shanggou.utils

import android.support.v4.util.LruCache
import android.text.TextUtils
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.huanglejing.mylibrary.KLog
import com.huanglejing.shanggou.common.AppContext
import com.huanglejing.shanggou.data.CacheCustomerId
import com.huanglejing.shanggou.rx.RxUtils
import rx.Observable
import rx.functions.Action1
import rx.schedulers.Schedulers
import java.io.File

object CacheLoader {
    private val TAG = "CacheLoader"

    private fun initMemCache(): LruCache<String, String> {
        val maxMemory = Runtime.getRuntime().maxMemory().toInt()
        val cacheSize = if (maxMemory / 8 > 4 * 1024 * 1024) 4 * 1024 * 1024 else maxMemory
        KLog.d(TAG, "max cacheSize = ${FileUtil.formatFileSize(cacheSize.toLong())}")
        return object : LruCache<String, String>(cacheSize) { //4m
            override fun entryRemoved(evicted: Boolean, key: String?, oldValue: String?, newValue: String?) {
                KLog.d(String.format("entryRemoved : evicted = %s , key = %20s , oldValue = %30s , newValue = %30s", evicted.toString(), key, oldValue, newValue))
                if (evicted) oldValue.let { null } ?: oldValue.let { newValue }
            }

            override fun sizeOf(key: String, value: String): Int {
                val length = value.toByteArray().size
                KLog.d("key = $key  sizeOf = [$length]bytes format:${FileUtil.formatFileSize((this.size() + length).toLong())}")
                return length
            }

        }
    }

    @JvmStatic
    val lru: LruCache<String, String> by lazy {
        initMemCache()
    }


    @JvmStatic
    val acache: ACache  by lazy {
        val path = AppContext.get().filesDir.absolutePath + "/cfzx_cache"
        ACache.get(File(path))
    }

    @JvmStatic
    val historyCache: ACache  by lazy {
        val path = AppContext.get().filesDir.absolutePath + "/cfzx_cache/list_history/${CacheCustomerId ?: "default"}"
        ACache.get(File(path))
    }


    fun fromLruMem(vararg keys: String): Observable<String> {
        return Observable.from(keys).map { s ->
            val s1 = lru.get(s)
            KLog.d(TAG, "from fromLruMem", s, s1)
            return@map s1
        }.subscribeOn(Schedulers.io())

    }

    fun fromACache(add2Lru: Boolean = true, vararg keys: String): Observable<String> {
        if (add2Lru)
            return Observable.from(keys).map { s ->
                val `var` = acache.getAsString(s)
                KLog.d(TAG, "from fromACache need add2Lru", s, `var`)
                arrayOf(s, `var`)
            }.doOnNext(Action1<kotlin.Array<kotlin.String>> { s ->
                KLog.d(TAG, "add ro lru", s[0], s[1])
                if (TextUtils.isEmpty(s[0]) || TextUtils.isEmpty(s[1])) return@Action1
                lru.put(s[0], s[1])
            }).map { strings -> strings[1] }.subscribeOn(Schedulers.io())
        else {
            return Observable.from(keys).map { s ->
                val `var` = acache.getAsString(s)
                KLog.d(TAG, "from fromACache not add2Lru", s, `var`)
                arrayOf(s, `var`)
            }.map { strings -> strings[1] }.subscribeOn(Schedulers.io())
        }
    }

    fun justLruMem2Json(key: String): Observable<JsonObject> {
        return fromLruMem(key).filter(RxUtils.SNoNull).map { s -> JsonParser().parse(s).asJsonObject }.subscribeOn(Schedulers.io())
    }

    fun justACache2Json(add2Lru: Boolean, key: String): Observable<JsonObject> {
        return fromACache(add2Lru, key).filter(RxUtils.SNoNull).map { s -> JsonParser().parse(s).asJsonObject }.subscribeOn(Schedulers.io())
    }

    fun <T> justLruMem2T(key: String, clz: Class<T>): Observable<T> {
        return fromLruMem(key).filter(RxUtils.SNoNull).map { s -> AppContext.gson().fromJson(s, clz) }.subscribeOn(Schedulers.io())
    }

    fun <T> justACache2T(add2Lru: Boolean, key: String, clz: Class<T>): Observable<T> {
        return fromACache(add2Lru, key).filter(RxUtils.SNoNull).map { s -> AppContext.gson().fromJson(s, clz) }.subscribeOn(Schedulers.io())
    }

    fun <T> contactLruAcahe2T(key: String, clz: Class<T>): Observable<T> {
        return Observable.concat(justLruMem2T(key, clz), justACache2T(true, key, clz)).first { it != null }
    }

    /**
     * 删除内存和磁盘缓存
     * @param key
     */
    fun removeCache(key: String) {
        lru.remove(key)
        acache.remove(key)
    }

    /**
     * 删除内存和磁盘缓存
     * @param key 包含key的缓存key
     */
    /*    fun removeCacheLike(key: String) {
            Schedulers.computation().createWorker().schedule {
                lru.snapshot().keys.filter { it.contains(key) }.forEach {
                    lru.remove(it);acache.remove(it)
                }
            }
        }*/

    fun removeCacheLike(vararg keys: String, isRegex: Boolean = false) {
        Schedulers.computation().createWorker().schedule {
            lru.snapshot().keys.let { cacheCopyKeys ->
                keys.forEach { removeKey ->
                    val filterAction: (String) -> Boolean = { s -> if (isRegex) s.contains(removeKey.toRegex()) else s.contains(removeKey) }
                    cacheCopyKeys.filter(filterAction).forEach {
                        KLog.d("removeCacheLike : $it")
                        cacheCopyKeys.remove(it); lru.remove(it);acache.remove(it)
                    }
                }
            }

        }
    }


}
